import Dep from './observer/dep';
import { observe } from './observer/index'
import Watcher from './observer/watch';
import { isArray, nextTick, proxy, isObject, isString, isFunction } from './utils/index';
export function initState(vm) {
    const options = vm.$options;
    // 判断 传入了哪些数据
    if (options.data) {
        initData(vm)
    }
    if (options.props) {
        initPrors(vm)
    }
    if (options.computed) {
        initComputed(vm)
    }
    if (options.methods) {
        initMethods(vm)
    }
    if (options.watch) {
        initWatch(vm)
    }
}

// 初始化 data
function initData(vm) {
    let data = vm.$options.data
    // 判断 data 并给原型 添加一个 _data
    data = vm._data = typeof data === 'function' ? data.call(vm) : data
    // 将数据响应化
    observe(data)

    // 通过 vue.name 直接访问数据
    const keys = Object.keys(data)
    for (let i = 0; i < keys.length; i++) {
        proxy(vm, '_data', keys[i]);
    }
}

// 初始化 computed
function initComputed(vm) {
    const computed = vm.$options.computed
    // 设置 watcher 的容器
    const watchers = vm._computedWatchers = {}
    // 循环每个 计算属性
    for (let key in computed) {
        const userDef = computed[key]
        // 判断是对象还是函数
        const getter = isFunction(userDef) ? userDef : userDef.get
        // 存储 watcher，实例上的 _computedWatchers 也会存储
        watchers[key] = new Watcher(vm, getter, () => { }, { lazy: true })
        // 将数据响应式
        defineComputed(vm, key, userDef)
    }
}

function defineComputed(target, key, userDef) {
    const sharePropertyDef = {
        enumerable: true,
        configurable: true,
        set: () => { },
        get: () => { }
    }

    if (isFunction(userDef)) {
        sharePropertyDef.get = createComputedGetter(key)
    } else {
        sharePropertyDef.get = createComputedGetter(key)
        sharePropertyDef.set = userDef.set
    }
    // 响应化
    Object.defineProperty(target, key, sharePropertyDef)
}

function createComputedGetter(key) {
    return function () {
        // 获取当前 watcher
        const watcher = this._computedWatchers[key]
        if (watcher) {
            // 如果是 脏数据 就计算
            if (watcher.dirty) {
                watcher.evaluate()
            }
            // 如果 Dep.target 就应该 要渲染 其他的 父级（栈结构）的其他 watcher
            if (Dep.target) {
                watcher.depend()
            }
            return watcher.value
        }

    }
}

function initWatch(vm) {
    // watch{  a(){}, b:{}, c:[], d:'d'}
    const watch = vm.$options.watch;
    for (let key in watch) {
        // 取出后面 要执行的内容
        const handler = watch[key]

        if (isArray(handler)) {
            handler.forEach(handle => {
                createWatch(vm, key, handle)
            });
        } else {
            createWatch(vm, key, handler)
        }
    }
}

function createWatch(vm, exprOrFn, handler, options) {
    // 判断 后面的是 对象还是 字符串
    if (isObject(handler)) {
        options = handler;
        handler = handler.handler
    } else if (isString(handler)) {
        handler = vm[handler]
    }
    return vm.$watch(exprOrFn, handler, options)
}


export function stateMixin(Vue) {
    // 自定义 $nextTick的实现
    Vue.prototype.$nextTick = function (cb) {
        nextTick(cb)
    }
    // 自定义的 watch 实现
    Vue.prototype.$watch = function (exprOrFn, cb, options) {
        // 如果有传入 immediate 就要立即执行
        (options && options.immediate) && cb()
        new Watcher(this, exprOrFn, cb, { ...options, user: true })
    }
}

